﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

namespace iNet.Net.Html
{
	#region HtmlDocType
	/// <summary>
	/// 表示 HTML 文件類型宣告。
	/// </summary>
	public class HtmlDocType : HtmlElement
	{
		#region 建構子
		internal HtmlDocType(string str)
			: base(HtmlElementType.DocType, str)
		{ }
		#endregion
	}
	#endregion
	#region HtmlElement
	/// <summary>
	/// 表示一個 HTML 元素。
	/// </summary>
	public class HtmlElement
	{
		#region 欄位
		string _OriginalString;
		HtmlElementType _Type;
		#endregion
		#region 建構子
		internal HtmlElement(HtmlElementType type)
			: this(type, null)
		{ }
		internal HtmlElement(HtmlElementType type, string originalString)
		{
			_OriginalString = originalString;
			_Type = type;
		}
		#endregion
		#region OriginalString
		/// <summary>
		/// 取得原始 HTML 字串。
		/// </summary>
		public string OriginalString
		{
			get
			{
				return _OriginalString;
			}
		}
		#endregion
		#region SetOriginalString
		internal void SetOriginalString(string str)
		{
			_OriginalString = str;
		}
		#endregion
		#region ToString
		/// <summary>
		/// 取得原始 HTML 字串。
		/// </summary>
		/// <returns>原始 HTML 字串。</returns>
		public override string ToString()
		{
			return _OriginalString;
		}
		#endregion
		#region Type
		/// <summary>
		/// 取得元素類型。
		/// </summary>
		public HtmlElementType Type
		{
			get
			{
				return _Type;
			}
		}
		#endregion
	}
	#endregion
	#region HtmlElementType
	/// <summary>
	/// 表示 HTML 元素類型。
	/// </summary>
	public enum HtmlElementType
	{
		/// <summary>
		/// 標籤。
		/// </summary>
		Tag,
		/// <summary>
		/// 文字。
		/// </summary>
		Text,
		/// <summary>
		/// Script。
		/// </summary>
		Script,
		/// <summary>
		/// Style Sheet。
		/// </summary>
		Stylesheet,
		/// <summary>
		/// 註解。
		/// </summary>
		Comment,
		/// <summary>
		/// 文件類型宣告。
		/// </summary>
		DocType,
	}
	#endregion
	#region HtmlTag
	/// <summary>
	/// 表示一個 HTML 標籤。
	/// </summary>
	public class HtmlTag : HtmlElement
	{
		#region 欄位
		static Regex _AttrNameRegex = new Regex("^[a-zA-Z_\\-]+$");
		static Regex _AttrRegex = new Regex("\\s(?<Name>[a-zA-Z_\\-]+)=((\"(?<Value>[^\"]*)\"|'(?<Value>[^']*)')|(?<Value>[^\\s\\>]*))", RegexOptions.IgnoreCase);
		static Regex _EndTagRegex = new Regex(@"\<\s*(/.*|.*/)\s*\>", RegexOptions.Singleline);
		bool _IsEndTag;
		bool _IsStartTag;
		string _Name;
		static Regex _NameRegex = new Regex(@"^\<\s*/?\s*(?<Name>[a-zA-Z]+)\s?");
		static Regex _StartTagRegex = new Regex(@"\<\s*[^/]+.*\>", RegexOptions.Singleline);
		#endregion
		#region 建構子
		internal HtmlTag(string str)
			: base(HtmlElementType.Tag, str)
		{
			//取得標籤性質
			Match match = _NameRegex.Match(str);
			_Name = (match.Success ? match.Groups["Name"].Value.ToLower() : null);
			_IsEndTag = _EndTagRegex.IsMatch(str);
			_IsStartTag = _StartTagRegex.IsMatch(str);
		}
		#endregion
		#region GetAttribute
		/// <summary>
		/// 取得標籤中指定名稱的屬性值。
		/// </summary>
		/// <param name="name">屬性名稱。</param>
		/// <returns>屬性值，Null (Visual Basic 為 Nothing) 表示沒有該屬性。</returns>
		/// <exception cref="ArgumentNullException">name 參數值為 Null (Visual Basic 為 Nothing)。</exception>
		/// <exception cref="ArgumentException">無效的 name 參數值。</exception>
		public string GetAttribute(string name)
		{
			//確認
			if (name == null)
				throw new ArgumentNullException("name");
			if (!_AttrNameRegex.IsMatch(name))
				throw new ArgumentException();

			//搜尋屬性
			Regex regex = new Regex(@"\s" + name.Replace("-", "\\-") + "=((\"(?<Value>[^\"]*)\"|'(?<Value>[^']*)')|(?<Value>[^\\s\\>]*))", RegexOptions.IgnoreCase);
			Match match = regex.Match(this.OriginalString);

			//取出屬性值
			if (match.Success)
				return match.Groups["Value"].Value;
			return null;
		}
		#endregion
		#region GetAttributes
		/// <summary>
		/// 取得標籤中所有的屬性，屬性名稱會全部轉為小寫。
		/// </summary>
		/// <returns>所有的 屬性名稱-值 對應。</returns>
		public Dictionary<string, string> GetAttributes()
		{
			//建立物件
			Dictionary<string, string> attributes = new Dictionary<string, string>();

			//取出屬性
			Match match = _AttrRegex.Match(this.OriginalString);
			while (match.Success)
			{
				attributes[match.Groups["Name"].Value.ToLower()] = match.Groups["Value"].Value;
				match = match.NextMatch();
			}

			//回傳
			return attributes;
		}
		#endregion
		#region IsEndTag
		/// <summary>
		/// 取得是否為結束標籤，例如 &lt;/body&gt; 或 &lt;br/&gt;。
		/// </summary>
		public bool IsEndTag
		{
			get
			{
				return _IsEndTag;
			}
		}
		#endregion
		#region IsStartTag
		/// <summary>
		/// 取得是否為開始標籤，例如 &lt;body&gt; 或 &lt;br/&gt;。
		/// </summary>
		public bool IsStartTag
		{
			get
			{
				return _IsStartTag;
			}
		}
		#endregion
		#region Name
		/// <summary>
		/// 取得標籤名稱，名稱全部以小寫表示。
		/// </summary>
		public string Name
		{
			get
			{
				return _Name;
			}
		}
		#endregion
	}
	#endregion
}